home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The X-Philes (2nd Revision)
/
The X-Philes Number 1 (1995).iso
/
xphiles
/
hp95
/
freyja13.exe
/
lha
/
DATE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-22
|
9KB
|
418 lines
/* DATE.C -- Calendar Routines
Written June 1991 by Craig A. Finseth
Copyright 1991 by Craig A. Finseth
*/
#include "freyja.h"
#if defined(MSDOS)
#include <time.h>
time_t time();
struct tm *localtime();
#endif
#define SYS_CAL "%cal%"
#define CAL_WIDTH 35
/* Cumulative month start day number. Yes, I know this has 13
months. */
static int mdays[] = {
0,
0 + 31,
0 + 31 + 28,
0 + 31 + 28 + 31,
0 + 31 + 28 + 31 + 30,
0 + 31 + 28 + 31 + 30 + 31,
0 + 31 + 28 + 31 + 30 + 31 + 30,
0 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 };
char *daynames[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "" };
char *monthnames[] = { "January", "Febuary", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December" };
static FLAG initted = FALSE; /* for current calendar */
static int cal_month;
static int cal_year;
static int cal_start = 0; /* starting day of week, 0 = Sunday */
void D_Calendar(); /* void */
void D_MakeConsistent(); /* int *yearptr, int *monptr */
/* ------------------------------------------------------------ */
/* Create and insert a calendar. */
void
DCal()
{
struct tm t;
if (!initted) {
initted = TRUE;
DNow(&t);
cal_month = t.tm_mon;
cal_year = t.tm_year;
}
if (!isuarg) ;
else if (uarg < 100) {
cal_month = uarg;
}
else if (uarg < 10000) {
cal_year = uarg;
}
else {
cal_year = uarg % 10000;
cal_month = uarg / - 1;
}
D_MakeConsistent(&cal_year, &cal_month);
D_Calendar();
uarg = 0;
}
/* ------------------------------------------------------------ */
/* Change the calendar by NUM months. */
void
DMove(num)
int num;
{
struct tm t;
if (!initted) {
initted = TRUE;
DNow(&t);
cal_month = t.tm_mon;
cal_year = t.tm_year;
}
cal_month += num;
D_MakeConsistent(&cal_year, &cal_month);
D_Calendar();
}
/* ------------------------------------------------------------ */
/* Advance the calendar by UARG months. */
void
DNext()
{
if (!isuarg) uarg = 1;
DMove(uarg);
uarg = 0;
}
/* ------------------------------------------------------------ */
/* Return the current date and time in TPTR. */
void
DNow(tptr)
struct tm *tptr;
{
time_t now;
#if defined(SYSMGR)
JGetDate(&tptr->tm_year, &tptr->tm_mon, &tptr->tm_mday);
#else
now = time(NULL);
*tptr = *localtime(&now);
tptr->tm_year += 1900;
#endif
}
/* ------------------------------------------------------------ */
/* Return the day of the week (0 = Sunday) for the supplied day number. */
int
DOW(day)
long day;
{
return((day + 0) % 7);
}
/* ------------------------------------------------------------ */
/* Rewind the calendar by UARG months. */
void
DPrev()
{
if (!isuarg) uarg = 1;
DMove(-uarg);
uarg = 0;
}
/* ------------------------------------------------------------ */
/* Setup the day of week start (0=sunday). */
void
DSetup(weekstart)
int weekstart;
{
cal_start = weekstart;
}
/* ------------------------------------------------------------ */
/* Convert the day number to a date. CAL is 0=360 day, 2=365 day,
other=actual. Should do sanity checking, but... */
void
DToDate(tptr, day, cal)
struct tm *tptr;
long day;
int cal;
{
long dn;
long ltmp;
memset((char *)tptr, NUL, sizeof(*tptr));
switch (cal) {
case 0:
tptr->tm_year = day / 360;
tptr->tm_mon = (day % 360) / 30;
tptr->tm_mday = (day % 30) + 1;
break;
case 2:
tptr->tm_year = day / 365;
day %= 365;
for (tptr->tm_mon = 0;
day >= mdays[tptr->tm_mon + 1];
tptr->tm_mon++) ;
tptr->tm_mday = day - mdays[tptr->tm_mon] + 1;
break;
default:
/* Divide the day number by 365.2422 to get real close to the correct
year. We must do this with ints, so multiply by 10,000 and divide by
3652422. But our day numbers range up to 9999 * 366 (or so) =
3,600,000. Multiplying by 10,000 exceeds a 32-bit int. We have to
reduce the 10,000 by a factor of 20 or so in order not to overflow.
If we call the orgininal number 365.2425 and so get 10,000 and
3652425, we can remove a factor of 25 and obain 400 and 146,097. This
works but is incorrect to the tune of 3 parts in (roughly) 3,000,000
or 1 in 1,000,000. As there are only about 2,500 leap year days that
can foul things up, we are still close enough. Later steps will
correct any error. */
ltmp = day * 400;
ltmp /= 146097;
/* Now the corrections start. First, make sure that we are before the
correct year. */
tptr->tm_year = ltmp - 2;
/* Now, count up until we get to the correct year. */
tptr->tm_mon = 0;
tptr->tm_mday = 1;
for (dn = 0; dn < day; tptr->tm_year++) {
dn = DToDayN(tptr, 1);
if (dn == day) return; /* done! */
}
tptr->tm_year -= 2;
/* We now have the correct year. On to the month and day. */
day -= DToDayN(tptr, 1);
if (day < mdays[1]) {
tptr->tm_mday = day + 1; /* Jan */
return;
}
else if (day < mdays[2]) {
tptr->tm_mon = 1;
tptr->tm_mday = day - mdays[1] + 1; /* Feb 28 */
return;
}
/* It is either Feb 29 (if we have a leap year), or some day after that */
/* See if we are a leap year. */
if (tptr->tm_year / 4 == 0 &&
(tptr->tm_year / 100 != 0 ||
tptr->tm_year / 400 == 0)) { /* leap year */
if (day == mdays[2]) {
tptr->tm_mon = 1;
tptr->tm_mday = 29;
return;
}
day--; /* treat as regular day */
}
for (tptr->tm_mon = 2;
day >= mdays[tptr->tm_mon + 1];
tptr->tm_mon++) ;
tptr->tm_mday = day - mdays[tptr->tm_mon] + 1;
break;
}
}
/* ------------------------------------------------------------ */
/* Convert the date to a day number and return the day number. CAL is
0=360 day, 2=365 day, other=actual. */
long
DToDayN(tptr, cal)
struct tm *tptr;
int cal;
{
long tmp;
int y;
int m;
int d;
y = tptr->tm_year;
m = tptr->tm_mon;
d = tptr->tm_mday;
D_MakeConsistent(&y, &m);
if (d < 1 || d > 31) d = 1;
switch (cal) {
case 0:
tmp = (360 * (long)y) + 30 * m + d - 1;
break;
case 2:
tmp = (365 * (long)y) + mdays[m] + d - 1;
break;
default:
tmp = (365 * (long)y) + mdays[m] + d - 1;
/* Jan and Feb get previous year's leap year counts */
if (m <= 1) y--;
tmp += y / 4; /* add leap years */
tmp -= y / 100; /* subtract non-leap cents. */
tmp += y / 400; /* add back 400 years */
break;
}
return(tmp);
}
/* ------------------------------------------------------------ */
/* Display a calendar, given a date. */
#if !defined(NOCALC)
void
DXCal(tptr)
struct tm *tptr;
{
initted = TRUE;
cal_month = tptr->tm_mon;
cal_year = tptr->tm_year;
D_MakeConsistent(&cal_year, &cal_month);
D_Calendar();
}
#endif
/* ------------------------------------------------------------ */
/* Display the calendar. */
void
D_Calendar()
{
struct tm t;
char buf[LINEBUFFSIZE];
int cnt;
int start;
int numdays;
long dayn;
if (!FMakeSys(SYS_CAL, TRUE)) return;
xsprintf(buf, "%s %4d\n", monthnames[cal_month], cal_year);
BInsSpaces((CAL_WIDTH - strlen(buf) - 1) / 2);
BInsStr(buf);
for (cnt = 0; cnt < 7; cnt++) {
xsprintf(buf, " %s ", daynames[(cnt + cal_start) % 7]);
BInsStr(buf);
}
BInsChar(NL);
t.tm_year = cal_year;
t.tm_mon = cal_month;
t.tm_mday = 1;
dayn = DToDayN(&t, 1);
start = DOW(dayn);
t.tm_mon++;
numdays = DToDayN(&t, 1) - dayn;
BInsSpaces(5 * start);
for (cnt = 1; cnt < numdays + 1; cnt++) {
xsprintf(buf, " %2d%c", cnt,
(cnt + start + cal_start) % 7 == 0 ? NL : SP);
BInsStr(buf);
}
BMoveBy(-1);
BCharDelete(1);
BInsChar(NL);
BMoveToStart();
}
/* ------------------------------------------------------------ */
/* Bring the month into the range 1-12 and adjust the year
accordingly. */
void
D_MakeConsistent(yearptr, monptr)
int *yearptr;
int *monptr;
{
while (*monptr > 11) {
(*monptr) -= 12;
(*yearptr)++;
}
while (*monptr < 0) {
(*monptr) += 12;
(*yearptr)--;
}
if (*yearptr > 9999) {
*monptr = 11;
*yearptr = 9999;
}
if (*yearptr < 1583) {
*monptr = 0;
*yearptr = 1583;
}
}
/* end of DATE.C -- Calendar Routines */